Conversation
WalkthroughIntroduce structured introspection configuration and secret-based skip logic; convert AccessController to an options-based constructor returning (controller, error); add introspection-aware authentication paths in the GraphQL prehandler; update router wiring, config schema/fixtures, and many tests to use the new APIs. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (8)
🚧 Files skipped from review as they are similar to previous changes (6)
🧰 Additional context used🧠 Learnings (2)📚 Learning: 2025-09-29T10:28:07.122ZApplied to files:
📚 Learning: 2025-09-23T16:27:54.358ZApplied to files:
🧬 Code graph analysis (2)router/core/supervisor_instance.go (2)
router-tests/websocket_test.go (2)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
🔇 Additional comments (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Router image scan passed✅ No security vulnerabilities found in image: |
…ion-endpoint-from-auth
|
fyi image scan fails because our distroless go image is vulnerable right now GoogleContainerTools/distroless#1863 Will wait for upstream fix and then rerun CI step, should fetch the updated image automatically and then it should work. EDIT: vulnerability fixed upstream. |
The deprecation logic of enabling introspection needed to be adjusted because it did not respect disabling introspection when only the new config parameter is used. Now when either the deprecated or the new config parameter disables introduction, it gets disabled regardless if the deprecated value enables it.
The default value for introspection.enabled is true but in router-tests due to the way config values are initiated, the value was false, which broke tests. This commit changes it by setting the value for introspection.enabled to it's default value 'true'.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (6)
router-tests/telemetry/telemetry_test.go (6)
9093-9094: Same as above for AccessController args and helper extraction.
9140-9141: Same as above for AccessController args and helper extraction.
9224-9225: Same as above for AccessController args and helper extraction.
9291-9292: Same as above for AccessController args and helper extraction.
9347-9348: Same as above for AccessController args and helper extraction.
9554-9555: Same as above for AccessController args and helper extraction.
🧹 Nitpick comments (18)
router/pkg/config/fixtures/full.yaml (1)
23-26: Clarify precedence with deprecated introspection_enabledThis fixture defines both the deprecated
introspection_enabledand the newintrospection.enabled. Please document or enforce precedence; ideally, drop the deprecated field from example fixtures to avoid confusion.Optional cleanup (outside the changed hunk):
-introspection_enabled: truerouter/core/router_config.go (1)
53-53: Expose new introspection settings in anonymized Usage() (without leaking the token)Add two booleans to Usage: whether skip-auth is enabled and whether a token is configured (do not export the token value).
Apply this diff:
@@ func (c *Config) Usage() map[string]any { - usage["introspection"] = c.introspection + usage["introspection"] = c.introspection + usage["introspection_skip_authentication"] = c.introspectionConfig.SkipAuthentication + usage["introspection_token_set"] = c.introspectionConfig.Token != ""router-tests/testenv/testenv.go (1)
1423-1425: Avoid mixing deprecated and new introspection APIsUsing both
WithIntrospection(true)andWithIntrospectionConfig(...)invites drift. Prefer the newWithIntrospectionConfigin tests.Apply this diff:
- core.WithIntrospection(true), - core.WithIntrospectionConfig(config.IntrospectionConfiguration{ - Enabled: true, - }), + core.WithIntrospectionConfig(config.IntrospectionConfiguration{ + Enabled: true, + }),router/pkg/config/testdata/config_full.json (1)
462-466: Document header semantics for the tokenPlease confirm in docs/schema whether the token must be sent as
Authorization: Bearer <token>or as a raw value, and how it interacts withSkipAuthentication. Define precedence if both are set.I can open a docs follow-up PR once confirmed.
router-tests/prometheus_test.go (1)
4131-4132: Reduce repetition of positional bool args with a test helperTo avoid future churn and improve readability across tests, consider a helper returning core.Option.
Apply this local replacement after adding the helper:
- core.WithAccessController(core.NewAccessController(authenticators, true, false, "")), + testenv.WithDefaultAccessController(authenticators, true),Add to testenv (or a shared test helper):
package testenv import ( "github.com/wundergraph/cosmo/router/core" "github.com/wundergraph/cosmo/router/pkg/authentication" ) func WithDefaultAccessController(authenticators []authentication.Authenticator, requireAuth bool) core.Option { return core.WithAccessController(core.NewAccessController(authenticators, requireAuth, false, "")) }router/core/router.go (2)
225-233: Make deprecation sync deterministic and avoid noisy warningsCurrent logic logs a deprecation warning whenever the old flag is false, even if the new config wasn’t used and there’s no divergence. Also, the else-if branch silently rewrites the old flag without warning. Prefer: warn only when values diverge and make “false wins” explicit for safety.
- // handle introspection config deprecation - // if either the old deprecated or the new config is set to false, introspection is disabled - if !r.introspection { - r.introspectionConfig.Enabled = r.introspection - r.logger.Warn("The introspection_enabled option is deprecated. Use the introspection.enabled option in the config instead.") - } else if !r.introspectionConfig.Enabled { - r.introspection = r.introspectionConfig.Enabled - } + // handle introspection config deprecation + // If values diverge, prefer safer behavior: false wins, and emit a single deprecation warning. + if r.introspection != r.introspectionConfig.Enabled { + if !r.introspection || !r.introspectionConfig.Enabled { + r.introspection = false + r.introspectionConfig.Enabled = false + } + r.logger.Warn("The introspection_enabled option is deprecated. Use introspection.enabled instead. Diverging values detected; 'false' takes precedence.") + }
1560-1565: Avoid shadowing the imported config packageRename the parameter to align with nearby options and avoid overshadowing the config import.
-func WithIntrospectionConfig(config config.IntrospectionConfiguration) Option { +func WithIntrospectionConfig(cfg config.IntrospectionConfiguration) Option { return func(r *Router) { - r.introspectionConfig = config + r.introspectionConfig = cfg } }router-tests/websocket_test.go (1)
140-140: Signature updates look correct; consider a small helper and verify for stragglersAll call sites correctly pass the two new args (skip introspection auth, token). To reduce repetition/noise across tests, consider a tiny helper (e.g., newAccessController(authenticators, requireAuth bool)) that supplies the defaults false,"".
Run to ensure no remaining 2-arg constructor calls:
#!/bin/bash # Find legacy usages of NewAccessController with exactly two arguments rg -nP --type go '\bNewAccessController\s*\(\s*[^,()]+\s*,\s*[^,()]+\s*\)'Also applies to: 189-189, 240-240, 299-299, 361-361, 421-421, 470-470, 886-886
router-tests/block_operations_test.go (1)
132-133: Updated constructor args are consistent with the new APILooks good. Same optional helper suggestion as in other tests to avoid repeating false,"".
Also applies to: 286-287, 383-383
router-tests/telemetry/telemetry_test.go (1)
9044-9045: Confirm empty introspection token semantics; consider reducing repetition.
You pass NewAccessController(authenticators, false, false, ""). Please verify that an empty token ("") is treated as “no token configured” and cannot accidentally match an empty Authorization header value. Also confirm that skip-introspection-auth=false keeps auth enforced for introspection.
Minor: this 4-arg constructor appears multiple times. Consider a tiny helper to avoid call-site churn if the signature changes again.
Apply at call sites:
- core.WithAccessController(core.NewAccessController(authenticators, false, false, "")) + core.WithAccessController(newTestAccessController(authenticators))Add once in this file (or testenv):
func newTestAccessController(authenticators core.Authenticators) core.AccessController { return core.NewAccessController(authenticators, false, false, "") }router/pkg/config/config.go (1)
986-991: Don’t serialize empty token valuesAdd omitempty so empty tokens aren’t emitted back to YAML or logs via config dumps.
type IntrospectionConfiguration struct { Enabled bool `yaml:"enabled" envDefault:"true" env:"INTROSPECTION_ENABLED"` SkipAuthentication bool `yaml:"skip_authentication" envDefault:"false" env:"INTROSPECTION_SKIP_AUTHENTICATION"` - Token string `yaml:"token" env:"INTROSPECTION_TOKEN"` + Token string `yaml:"token,omitempty" env:"INTROSPECTION_TOKEN"` }router/core/supervisor_instance.go (2)
60-65: Enforce introspection token even without JWT authenticatorsAccessController is only created when authenticators exist. If users configure only an introspection token (no JWT), it never gets enforced.
- if len(authenticators) > 0 { + if len(authenticators) > 0 || cfg.IntrospectionConfig.SkipAuthentication || cfg.IntrospectionConfig.Token != "" { options = append(options, WithAccessController(NewAccessController( authenticators, cfg.Authorization.RequireAuthentication, cfg.IntrospectionConfig.SkipAuthentication, cfg.IntrospectionConfig.Token, ))) }
163-165: Use the new nested flag to control introspectionTo avoid contradictory settings between deprecated and new flags, drive WithIntrospection from IntrospectionConfig.Enabled.
- WithIntrospection(config.IntrospectionEnabled), + WithIntrospection(config.IntrospectionConfig.Enabled), WithIntrospectionConfig(config.IntrospectionConfig),router/core/access_controller.go (2)
20-24: Constructor grows boolean blindness; consider options struct.Two trailing booleans make call‑sites error‑prone and reduce readability. Prefer a single options struct (or functional options) to carry authenticationRequired, skipIntrospectionAuth, and the token.
Also applies to: 26-33
100-112: Accept “Bearer ” form for the introspection token.Current check requires the Authorization header to equal the raw token, which is surprising given normal usage. Allow both raw and “Bearer ” while keeping constant‑time compares.
Apply this diff:
func (a *AccessController) isValidIntrospectionToken(r *http.Request) bool { // If no token is configured, allow introspection without authentication if len(a.introspectionAuthSkipToken) == 0 { return true } authHeader := r.Header.Get("Authorization") if authHeader == "" { return false } - return subtle.ConstantTimeCompare([]byte(authHeader), []byte(a.introspectionAuthSkipToken)) == 1 + token := a.introspectionAuthSkipToken + // Accept exact token + if len(authHeader) == len(token) && + subtle.ConstantTimeCompare([]byte(authHeader), []byte(token)) == 1 { + return true + } + // Accept "Bearer <token>" + bearer := "Bearer " + token + if len(authHeader) == len(bearer) && + subtle.ConstantTimeCompare([]byte(authHeader), []byte(bearer)) == 1 { + return true + } + return false }router-tests/authentication_test.go (3)
2509-2725: Great coverage; add a few hardening cases.
- Mixed query (introspection + normal field) must not bypass auth.
- GET /graphql with introspection in query param (if supported) should get the same treatment.
- Authorization: "Bearer " should also bypass when a token is configured (post‑change in AccessController).
I can append subtests for these three scenarios; want a patch?
2621-2631: Secret scanner false positive; replace high‑entropy test token.Gitleaks flags the literal token as a generic API key. Use a clearly fake, low‑entropy value and centralize it.
Apply this diff (and reuse in all places):
@@ - token := "0aG3TVhkZ2lPy8ULUPQLXZ4JFPfpxk" + // Non‑secret, low‑entropy value to avoid triggering secret scanners. + token := "introspection-token-for-tests" // gitleaks:allow @@ - header := http.Header{ - "Authorization": []string{token}, - } + header := http.Header{ + "Authorization": []string{token}, + }Optionally, lift the token to a file‑level const near the other test constants and reference it here and at Line 2649.
2550-2555: Assert JSON semantically to reduce brittle string compares.For these response bodies, require.JSONEq improves robustness and readability.
- require.Equal(t, simpleIntrospectionExpectedData, string(data)) + require.JSONEq(t, simpleIntrospectionExpectedData, string(data))Also applies to: 2580-2584, 2606-2611, 2634-2639
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (22)
router-tests/authentication_test.go(68 hunks)router-tests/batch_test.go(2 hunks)router-tests/block_operations_test.go(3 hunks)router-tests/header_set_test.go(1 hunks)router-tests/modules/router_on_request_test.go(2 hunks)router-tests/modules/set_authentication_scopes_test.go(3 hunks)router-tests/modules/set_scopes_test.go(2 hunks)router-tests/prometheus_test.go(1 hunks)router-tests/ratelimit_test.go(1 hunks)router-tests/telemetry/telemetry_test.go(7 hunks)router-tests/testenv/testenv.go(1 hunks)router-tests/websocket_test.go(8 hunks)router/core/access_controller.go(3 hunks)router/core/graphql_prehandler.go(1 hunks)router/core/router.go(2 hunks)router/core/router_config.go(1 hunks)router/core/supervisor_instance.go(2 hunks)router/pkg/config/config.go(2 hunks)router/pkg/config/config.schema.json(1 hunks)router/pkg/config/fixtures/full.yaml(1 hunks)router/pkg/config/testdata/config_defaults.json(1 hunks)router/pkg/config/testdata/config_full.json(1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.27.2)
router/pkg/config/testdata/config_full.json
[high] 465-465: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
router-tests/authentication_test.go
[high] 2621-2621: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 2649-2649: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🔇 Additional comments (17)
router/pkg/config/testdata/config_defaults.json (1)
231-235: Defaults look good; confirm precedence vs. deprecated flag
IntrospectionConfig.Enableddefaults to true and coexists withIntrospectionEnabled. Ensure one has clear precedence across loaders/options and tests.Run to locate usages and confirm precedence in code:
#!/bin/bash rg -n -C2 -S '\bIntrospectionEnabled\b|\bIntrospectionConfig\b'router-tests/prometheus_test.go (1)
4131-4132: Aligns with new AccessController signature — looks goodPassing authenticationRequired=true with skipIntrospectionAuth=false and empty token preserves previous behavior while enabling the new API.
router-tests/batch_test.go (1)
340-341: Constructor updates match the expanded APIUsing false for authenticationRequired and skipIntrospectionAuth with an empty token maintains existing test semantics while adopting the new signature.
Also applies to: 748-749
router-tests/header_set_test.go (1)
284-286: JWT-claim header test correctly requires authenticationSwitch to the 4-arg constructor is accurate; requiring auth here is appropriate for claim extraction.
router-tests/modules/set_authentication_scopes_test.go (1)
37-39: AccessController calls updated consistentlyAll three sites now use the new constructor with defaults that preserve prior behavior for these scope-setting tests.
Also applies to: 78-80, 121-123
router-tests/modules/set_scopes_test.go (1)
66-68: New constructor usage is correct and consistentAdopts the expanded signature without changing test intent.
Also applies to: 106-108
router-tests/ratelimit_test.go (1)
275-277: Auth-aware rate limit test updated appropriatelyInjecting the AccessController via the new constructor is correct; keeping introspection bypass disabled matches the test’s purpose.
router-tests/modules/router_on_request_test.go (2)
8-10: Import aliasing LGTMAlias improves clarity in this suite.
75-76: AccessController call updated correctlyFour-arg usage matches the new signature; no issues.
router/pkg/config/config.schema.json (2)
1363-1368: Deprecation handling for introspection_enabled looks consistent.Defaults and deprecation messaging align with the new nested config and will minimize breakage.
1369-1390: ```shell
#!/bin/bash
set -euxFind where the Introspection config struct is defined
rg -nP 'type\s+\wIntrospection\w\s+' --type go
Inspect usages of skip_authentication in code paths handling introspection
rg -n 'skip_authentication' -C3 --type go
Check how token is used in introspection/auth handlers
rg -n 'introspection' -C3 --type go
rg -n 'token' -C3 --type go</blockquote></details> <details> <summary>router/core/supervisor_instance.go (1)</summary><blockquote> `60-65`: **Constant‑time token comparison** Ensure AccessController’s token check uses crypto/subtle.ConstantTimeCompare to avoid timing attacks. ```shell #!/bin/bash # Verify constant-time compare is used for introspection token checks rg -n -C2 -g '!**/vendor/**' -S 'isValidIntrospectionToken|ConstantTimeCompare|subtle\.' --type=gorouter/core/graphql_prehandler.go (1)
363-366: Gate bypass by “introspection enabled”Confirm BypassAuthIfIntrospection returns false when introspection is disabled to avoid skipping auth for queries that will be blocked anyway.
router/core/access_controller.go (2)
4-4: Good choice: constant‑time compare for token.Importing crypto/subtle avoids timing leaks on token checks.
53-96: Ensure bypass only for introspection‑only operations.Please confirm OperationKit.isIntrospectionQuery returns true only when the operation contains exclusively introspection fields. If mixed queries (e.g., { __schema ... employees { id } }) also return true, this would create an auth bypass for normal data. Add a test that proves mixed queries do NOT bypass auth.
I can add a test variant to TestIntrospectionAuthentication that sends a mixed query and expects 401 when authentication is required. Want me to draft it?
router-tests/authentication_test.go (2)
46-47: Constructor call‑sites updated correctly.All usages migrated to the 4‑arg NewAccessController; behavior preserved.
Also applies to: 67-68, 91-92, 117-118, 135-136, 160-161, 187-188, 213-214, 240-241, 271-272, 300-301, 325-326, 348-349, 375-376, 402-403, 431-432, 451-452, 471-472, 491-492, 516-517, 543-544, 570-571, 597-598, 654-655, 715-716, 736-737, 762-763, 815-816, 875-876, 918-919, 957-958, 1000-1001, 1219-1220, 1247-1248, 1368-1369, 1451-1452, 1473-1474, 1495-1496, 1521-1522, 1547-1548, 1582-1583, 1628-1629, 1657-1658, 1686-1687, 1715-1716, 1744-1745, 1773-1774, 1806-1807, 1835-1836, 1864-1865, 1897-1898, 1929-1930, 1960-1961, 1988-1989, 2019-2020, 2054-2055, 2110-2111, 2150-2151, 2194-2195, 2234-2235, 2283-2284, 2324-2325, 2368-2369, 2408-2409, 2450-2451, 2490-2491, 2519-2520
2649-2659: Repeat of the gitleaks issue above.Use the same low‑entropy constant here to keep scanners green.
After the change, rerun the secret scan job to confirm the alert is gone.
The env var INTROSPECTION_ENABLED was used twice to populate both, the new and deprecated config parameters. This is solved by removing it from the deprecated config value. There is deprecation logic in code active which will set the value for both parameters.
SkArchon
left a comment
There was a problem hiding this comment.
Good PR, main question related to GET request and parsing
endigma
left a comment
There was a problem hiding this comment.
I have some thoughts about duplicating/moving the operationkit, but here's some other things that should come first.
Instead of introspection.skip_authentication now provide introspection.authentication_mode with 3 choices: full = normal jwt auth for introspection queries skip = skip auth for introspection queries token = use static token for introspection queries
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (17)
router/core/router.go (1)
225-232: Strengthen deprecation handling and messaging when flags conflictCurrently you warn only when the legacy flag disables introspection; also warn when the new config disables it while the legacy flag is true, and standardize the path format to “/introspection/enabled”.
// handle introspection config deprecation // if either the old deprecated or the new config is set to false, introspection is disabled if !r.introspection { - r.introspectionConfig.Enabled = r.introspection - r.logger.Warn("The introspection_enabled option is deprecated. Use the introspection.enabled option in the config instead.") + r.introspectionConfig.Enabled = r.introspection + r.logger.Warn("The legacy 'introspection_enabled' option is deprecated. Use '/introspection/enabled' instead.") } else if !r.introspectionConfig.Enabled { - r.introspection = r.introspectionConfig.Enabled + r.introspection = r.introspectionConfig.Enabled + r.logger.Warn("The legacy 'introspection_enabled' option is deprecated. '/introspection/enabled=false' overrides the legacy flag when they conflict.") }router-tests/websocket_test.go (13)
195-195: Same WithAccessController wiring — OKMatches the new API usage pattern.
241-242: OK to construct controller here as wellPattern mirrors earlier block.
248-248: OK: controller passed via optionConsistent with prior change.
302-303: Controller ctor + error check — OKNo concerns.
309-309: WithAccessController usage — OK
362-363: Controller ctor with required=true — OKAppropriate for “auth via initial payload” scenarios.
373-373: WithAccessController usage — OK
426-427: Controller ctor — OK
435-435: WithAccessController usage — OK
477-478: Controller ctor — OK
486-486: WithAccessController usage — OK
880-881: Controller ctor — OK
903-903: WithAccessController usage — OKrouter/pkg/config/config.go (1)
1018-1020: Resolved env var collision on deprecated flag.
Removing env tag from IntrospectionEnabled prevents conflicts; nested config is now SoT.router/core/graphql_prehandler.go (1)
358-389: Nice: no span leak—Authenticate span created only when used.
This addresses the earlier leak concern cleanly.router/core/access_controller.go (1)
101-131: Support GET-based introspection detection.
Without this, ?query=… introspection over GET never bypasses auth.-// isIntrospectionQuery checks if the operation in body is an introspection query. -// It returns false if the operation is not an introspection query or we cannot parse it. -func isIntrospectionQuery(operationProcessor *OperationProcessor, body []byte) bool { - if operationProcessor == nil || body == nil { - return false - } - operationKit, err := operationProcessor.NewKit() - if err != nil { - return false - } - defer operationKit.Free() - err = operationKit.UnmarshalOperationFromBody(body) - if err != nil { - return false - } +// isIntrospectionRequest checks if the HTTP request is an introspection query (POST or GET). +// It returns false if the operation is not introspection or cannot be parsed. +func isIntrospectionRequest(r *http.Request, operationProcessor *OperationProcessor, body []byte) bool { + if operationProcessor == nil { + return false + } + operationKit, err := operationProcessor.NewKit() + if err != nil { + return false + } + defer operationKit.Free() + switch r.Method { + case http.MethodGet: + if err = operationKit.UnmarshalOperationFromURL(r.URL); err != nil { + return false + } + default: + if body == nil { + return false + } + if err = operationKit.UnmarshalOperationFromBody(body); err != nil { + return false + } + } err = operationKit.Parse() if err != nil { return false } isIntrospection, err := operationKit.isIntrospectionQuery() if err != nil { return false } return isIntrospection }
🧹 Nitpick comments (15)
router-tests/testenv/testenv.go (1)
1422-1424: API update LGTM (consider explicit auth mode for clarity)Passing Enabled: true is fine; consider also setting AuthenticationMode: "full" to make the test resilient to future default changes.
- core.WithIntrospection(true, config.IntrospectionConfiguration{ - Enabled: true, - }), + core.WithIntrospection(true, config.IntrospectionConfiguration{ + Enabled: true, + AuthenticationMode: "full", + }),router/core/router.go (1)
1554-1558: Avoid shadowing the imported config packageThe parameter name “config” shadows the imported package; rename to cfg for clarity.
-func WithIntrospection(enable bool, config config.IntrospectionConfiguration) Option { +func WithIntrospection(enable bool, cfg config.IntrospectionConfiguration) Option { return func(r *Router) { r.introspection = enable - r.introspectionConfig = config + r.introspectionConfig = cfg } }router-tests/prometheus_test.go (1)
4122-4124: Optional: DRY up AccessController setup across testsConsider a tiny helper to reduce repetition.
// testutil/test_access.go func NewTestAccessController(t *testing.T, auth []authentication.Authenticator, required bool) *core.AccessController { t.Helper() ac, err := core.NewAccessController(auth, required, core.IntrospectionAuthModeFull, "") require.NoError(t, err) return ac }Then replace local constructions with
testutil.NewTestAccessController(t, authenticators, true).Also applies to: 4134-4134
router-tests/header_set_test.go (1)
278-280: Optional: extract a shared helper for AccessController creationSame helper as suggested in prometheus tests would keep these call sites concise.
Also applies to: 287-287
router-tests/ratelimit_test.go (1)
273-275: Optional: unify controller setupAdopt the same small helper to create the controller (with required=false in this test) to keep tests consistent and terse.
Also applies to: 278-279
router-tests/websocket_test.go (1)
190-192: Reduce repetition: extract a tiny helper for AccessController setupThis exact pattern repeats throughout the file; a helper will shrink noise and ease future API tweaks.
Apply locally where used:
- accessController, err := core.NewAccessController(authenticators, false, core.IntrospectionAuthModeFull, "") - require.NoError(t, err) + accessController := mustAccessController(t, authenticators, false)Add once in this test file:
func mustAccessController(t *testing.T, authenticators []authentication.Authenticator, required bool) *core.AccessController { t.Helper() ac, err := core.NewAccessController(authenticators, required, core.IntrospectionAuthModeFull, "") require.NoError(t, err) return ac }router-tests/telemetry/telemetry_test.go (1)
9031-9033: DRY up repeated controller construction across subtestsThe NewAccessController + require.NoError pattern is repeated in several subtests. Consider a tiny helper to reduce noise and make future signature changes easier.
Apply this local replacement in one spot as an example:
- authenticators, authServer := integration.ConfigureAuth(t) - accessController, err := core.NewAccessController(authenticators, false, core.IntrospectionAuthModeFull, "") - require.NoError(t, err) + authenticators, authServer := integration.ConfigureAuth(t) + accessController := mustNewAccessController(t, authenticators) ... - RouterOptions: []core.Option{ - core.WithAccessController(accessController), - }, + RouterOptions: []core.Option{ + core.WithAccessController(accessController), + },Add this helper in the same file (or a shared test util):
// at file scope // import "github.com/wundergraph/cosmo/router/pkg/authentication" func mustNewAccessController(t *testing.T, authenticators []authentication.Authenticator) *core.AccessController { t.Helper() ac, err := core.NewAccessController(authenticators, false, core.IntrospectionAuthModeFull, "") require.NoError(t, err) return ac }Also applies to: 9047-9048
router/pkg/config/config.go (1)
986-990: Add type-safety and env-only validation for AuthenticationMode.
Consider using a typed alias matching core.IntrospectionAuthMode and validating env-only runs (when no YAML is loaded) to avoid invalid values slipping through.Apply:
type IntrospectionConfiguration struct { Enabled bool `yaml:"enabled" envDefault:"true" env:"INTROSPECTION_ENABLED"` - AuthenticationMode string `yaml:"authentication_mode" envDefault:"full" env:"INTROSPECTION_AUTHENTICATION_MODE"` + AuthenticationMode string `yaml:"authentication_mode" envDefault:"full" env:"INTROSPECTION_AUTHENTICATION_MODE"` Token string `yaml:"token" env:"INTROSPECTION_TOKEN"` }And after env.Parse in LoadConfig, validate:
if err := env.Parse(&cfg.Config); err != nil { return nil, err } +// Validate env-only introspection mode (schema validation won’t run without YAML) +switch cfg.Config.IntrospectionConfig.AuthenticationMode { +case "full", "token", "skip": +default: + return nil, fmt.Errorf("invalid INTROSPECTION_AUTHENTICATION_MODE: %q (allowed: full|token|skip)", cfg.Config.IntrospectionConfig.AuthenticationMode) +}router/core/graphql_prehandler.go (1)
358-389: Expose an attribute when auth is bypassed for observability.
Helps tracing/metrics dashboards distinguish bypassed flows.Apply:
- if !skipAuth { + if !skipAuth { _, authenticateSpan := h.tracer.Start(r.Context(), "Authenticate", trace.WithSpanKind(trace.SpanKindServer), trace.WithAttributes(requestContext.telemetry.traceAttrs...), ) … } + if skipAuth { + routerSpan.SetAttributes(attribute.Bool("wg.auth.bypassed", true)) + }router/pkg/config/config.schema.json (1)
1369-1400: Tighten schema docs and hide secret in tooling.
Add descriptions and mark token writeOnly; warn against production “skip”."introspection": { "type": "object", - "description": "", + "description": "GraphQL introspection settings. For production, prefer 'full' or 'token'. Using 'skip' is not recommended.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", - "description": "", + "description": "Enable GraphQL introspection.", "default": true }, "authentication_mode": { "type": "string", "enum": ["full", "token", "skip"], - "description": "Authentication mode for introspection queries. 'full' requires normal authentication, 'token' requires a specific introspection token, 'skip' bypasses authentication entirely.", + "description": "How to authenticate introspection queries. 'full' = require normal auth; 'token' = require a dedicated introspection token; 'skip' = no auth (not recommended for production).", "default": "full" }, "token": { "type": "string", - "description": "Token to authenticate introspection requests. Required when introspection.authentication_mode is set to 'token', ignored otherwise.", + "description": "Static secret for introspection requests when authentication_mode = 'token'.", + "writeOnly": true, "minLength": 32 } },router/core/access_controller.go (1)
35-39: Name nit: introspectionAuthSkipToken reads oddly in “token” mode.
Consider renaming to introspectionAuthToken for clarity.router-tests/authentication_test.go (4)
2818-2823: Test name/comment mismatch with behavior (ModeSkip ignores token)You configure a token but run in IntrospectionAuthModeSkip where the token is intentionally ignored. Rename/comment to reflect that.
Apply:
- t.Run("introspection query with auth skip and introspection token", func(t *testing.T) { + t.Run("introspection query with auth skip (token ignored)", func(t *testing.T) { @@ - // since we are skipping auth for introspection and have not configured - // a dedicated token for introspection queries, this query must succeed + // ModeSkip bypasses auth for introspection; any configured token is ignored.
2850-2857: Test name mismatch: not “auth skip”, this is token modeThis subtest uses IntrospectionAuthModeToken; rename for clarity.
- t.Run("introspection query with auth skip and invalid introspection token", func(t *testing.T) { + t.Run("introspection query with token mode and invalid introspection token", func(t *testing.T) {
2701-2939: Add positive coverage for token mode and clarify header formatYou cover ModeToken (negative) but not the happy path. Also, header format for the introspection token (raw vs "Bearer ") isn’t asserted.
- Add a passing case for ModeToken:
+ t.Run("introspection query with token mode and valid introspection token", func(t *testing.T) { + t.Parallel() + authenticators, _ := ConfigureAuth(t) + token := "wg_test_introspection_token" // test-only token; gitleaks:allow + accessController, err := core.NewAccessController(authenticators, true, core.IntrospectionAuthModeToken, token) + require.NoError(t, err) + testenv.Run(t, &testenv.Config{ + RouterOptions: []core.Option{core.WithAccessController(accessController)}, + }, func(t *testing.T, xEnv *testenv.Environment) { + header := http.Header{"Authorization": []string{token}} + res, err := xEnv.MakeRequest(http.MethodPost, "/graphql", header, strings.NewReader(simpleIntrospectionQuery)) + require.NoError(t, err) + defer res.Body.Close() + require.Equal(t, http.StatusOK, res.StatusCode) + require.Equal(t, "", res.Header.Get(xAuthenticatedByHeader)) + data, _ := io.ReadAll(res.Body) + require.Equal(t, simpleIntrospectionExpectedData, string(data)) + }) + })
- If ModeToken accepts a Bearer prefix as well, mirror the above with:
header := http.Header{"Authorization": []string{"Bearer " + token}}Please confirm expected header semantics; if only raw is supported, we should document that invariant in the test name/comments.
2701-2939: Minor duplication: helper for AccessController setupConsider a tiny local helper to cut the repeated NewAccessController boilerplate across subtests and reduce mistakes.
Example:
newAC := func(t *testing.T, authRequired bool, mode core.IntrospectionAuthMode, token string, auths ...authentication.Authenticator) *core.AccessController { ac, err := core.NewAccessController(auths, authRequired, mode, token) require.NoError(t, err) return ac }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
router-tests/authentication_test.go(68 hunks)router-tests/batch_test.go(2 hunks)router-tests/block_operations_test.go(3 hunks)router-tests/header_set_test.go(1 hunks)router-tests/modules/router_on_request_test.go(2 hunks)router-tests/modules/set_authentication_scopes_test.go(3 hunks)router-tests/modules/set_scopes_test.go(2 hunks)router-tests/prometheus_test.go(2 hunks)router-tests/ratelimit_test.go(1 hunks)router-tests/security_test.go(2 hunks)router-tests/telemetry/telemetry_test.go(14 hunks)router-tests/testenv/testenv.go(1 hunks)router-tests/websocket_test.go(10 hunks)router/core/access_controller.go(3 hunks)router/core/graphql_prehandler.go(1 hunks)router/core/router.go(2 hunks)router/core/supervisor_instance.go(2 hunks)router/pkg/config/config.go(2 hunks)router/pkg/config/config.schema.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- router/core/supervisor_instance.go
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.
Applied to files:
router/pkg/config/config.schema.json
📚 Learning: 2025-09-02T12:52:27.677Z
Learnt from: endigma
PR: wundergraph/cosmo#2181
File: router/core/operation_processor.go:0-0
Timestamp: 2025-09-02T12:52:27.677Z
Learning: Hash validation for persisted queries with query bodies is performed in router/core/graphql_prehandler.go in the handleOperation function, not in the APQ processing logic in operation_processor.go. This validates that extensions.persistedQuery.sha256Hash matches the query body before any APQ operations occur.
Applied to files:
router/core/access_controller.go
📚 Learning: 2025-09-02T12:52:27.677Z
Learnt from: endigma
PR: wundergraph/cosmo#2181
File: router/core/operation_processor.go:0-0
Timestamp: 2025-09-02T12:52:27.677Z
Learning: Hash validation for persisted queries with query bodies is performed in router/core/graphql_prehandler.go in the handleOperation function at lines 571-578, not in the APQ processing logic in operation_processor.go. This validates that extensions.persistedQuery.sha256Hash matches the computed query hash before any APQ operations occur. There's also a test case that verifies this behavior.
Applied to files:
router/core/access_controller.go
🧬 Code graph analysis (16)
router-tests/security_test.go (2)
router/core/router.go (1)
WithIntrospection(1554-1559)router/pkg/config/config.go (1)
IntrospectionConfiguration(986-990)
router-tests/batch_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (3)
Option(172-172)WithAccessController(1825-1829)BatchingConfig(125-130)
router-tests/header_set_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (1)
WithAccessController(1825-1829)
router-tests/modules/set_authentication_scopes_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router-tests/testenv/testenv.go (2)
router/core/router.go (1)
WithIntrospection(1554-1559)router/pkg/config/config.go (1)
IntrospectionConfiguration(986-990)
router/core/access_controller.go (2)
router/pkg/authentication/authentication.go (1)
Authenticator(22-25)router/core/operation_processor.go (1)
OperationProcessor(124-136)
router-tests/prometheus_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (1)
WithAccessController(1825-1829)
router-tests/modules/set_scopes_test.go (3)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router_config.go (1)
Config(28-122)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router-tests/websocket_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router-tests/block_operations_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router-tests/authentication_test.go (3)
router/core/access_controller.go (4)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)IntrospectionAuthModeSkip(23-23)IntrospectionAuthModeToken(20-20)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)router-tests/utils.go (2)
ConfigureAuth(45-57)JwksName(19-19)
router-tests/ratelimit_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router-tests/modules/router_on_request_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router-tests/telemetry/telemetry_test.go (2)
router/core/access_controller.go (2)
NewAccessController(43-58)IntrospectionAuthModeFull(17-17)router/core/router.go (1)
WithAccessController(1825-1829)
router/core/router.go (1)
router/pkg/config/config.go (1)
IntrospectionConfiguration(986-990)
router/core/graphql_prehandler.go (2)
router/internal/expr/expr.go (3)
Context(35-39)Request(66-75)LoadAuth(183-195)router/pkg/trace/utils.go (1)
AttachErrToSpan(75-81)
🪛 Gitleaks (8.27.2)
router-tests/authentication_test.go
[high] 2825-2825: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
[high] 2855-2855: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: build-router
- GitHub Check: build_test
- GitHub Check: build_push_image
- GitHub Check: integration_test (./telemetry)
- GitHub Check: build_test
- GitHub Check: image_scan (nonroot)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (go)
- GitHub Check: integration_test (./events)
- GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
- GitHub Check: build_push_image (nonroot)
- GitHub Check: image_scan
🔇 Additional comments (29)
router-tests/security_test.go (1)
344-346: API update LGTMUpdated to WithIntrospection(false, config.IntrospectionConfiguration{Enabled: false}) matches the new signature and intent.
router-tests/batch_test.go (2)
336-343: AccessController construction updated correctlyUsing the new 4-arg constructor with error handling is correct; passing IntrospectionAuthModeFull and empty token matches prior behavior.
743-754: AccessController wiring LGTMCreating once and injecting via WithAccessController keeps tests clean and mirrors the new API.
router-tests/modules/set_authentication_scopes_test.go (6)
35-41: AccessController construction updated correctlyNew signature used with require.NoError; good.
39-43: Controller injection LGTMPassing the pre-built controller via RouterOptions is consistent across tests.
79-85: AccessController construction updated correctlyConsistent usage with IntrospectionAuthModeFull and empty token.
84-84: Controller injection LGTMMatches updated API.
125-127: AccessController construction updated correctlyGood to see error handling added.
130-130: Controller injection LGTMConsistent with the rest of the suite.
router/core/router.go (1)
1554-1558: No remaining single-arg WithIntrospection calls — all call sites now use the new two-arg signature.router-tests/modules/set_scopes_test.go (2)
64-70: AccessController construction and injection LGTMMatches the new API and keeps previous behavior.
107-113: Second occurrence LGTMConsistent and correct.
router-tests/prometheus_test.go (1)
4122-4124: LGTM: explicit AccessController with full introspection auth preserves previous semanticsConstructor args look right and the error is handled; wiring via WithAccessController is correct for claims-based metric extraction.
Also applies to: 4134-4134
router-tests/header_set_test.go (1)
278-280: LGTM: switched to new AccessController API with explicit modeUsing IntrospectionAuthModeFull and passing the controller via RouterOptions is correct for the auth-claim header rule test.
Also applies to: 287-287
router-tests/ratelimit_test.go (1)
273-275: LGTM: optional auth fits the claim-derived rate-limit key testauthenticationRequired=false is appropriate here to allow claim extraction without enforcing auth; controller is correctly injected.
Also applies to: 278-279
router-tests/websocket_test.go (2)
138-140: Explicit AccessController construction + error handling — OKUsing IntrospectionAuthModeFull with an empty token preserves previous WS auth semantics; error is properly asserted.
143-143: Pass pre-built controller via WithAccessController — OKSeparating construction from wiring improves clarity and makes failures visible.
router-tests/telemetry/telemetry_test.go (2)
9031-9033: LGTM: tests correctly adopt the new AccessController API and inject it via WithAccessController
- Constructing the controller with the new 4-arg signature and asserting require.NoError is correct.
- Passing the pointer into core.WithAccessController matches the updated Option contract.
- Using IntrospectionAuthModeFull maintains prior behavior for these telemetry tests.
Also applies to: 9047-9048, 9084-9086, 9099-9100, 9135-9137, 9149-9150, 9211-9213, 9236-9237, 9289-9291, 9306-9306, 9351-9352, 9365-9366, 9554-9556, 9574-9575
9031-9033: All NewAccessController calls updated to 4-arg constructor
No 2- or 3-argument usages remain.router-tests/modules/router_on_request_test.go (2)
8-10: LGTM: import aliasing looks fine.
73-79: Correct migration to new AccessController API.
Constructor + error handling + WithAccessController usage are all correct.router-tests/block_operations_test.go (3)
130-136: Good: centralized AccessController creation + error handling.
286-292: Good: migrated to injected access controller.
381-390: Good: consistent wiring across tests.router/pkg/config/config.schema.json (1)
1363-1368: Deprecation entry looks correct.
Clear message and default preserved.router/core/access_controller.go (2)
12-24: Enum definition is clear and future-proof.
41-58: Constructor validation is correct.
Erroring on invalid mode prevents misconfig at startup.router-tests/authentication_test.go (2)
27-34: Good addition: minimal introspection fixturesThe simple query/expected payload keeps tests fast and readable.
42-49: LGTM: explicit AccessController injectionMigrating tests to core.WithAccessController(accessController) is clean and aligns with the new constructor API.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
router/pkg/config/config_test.go (3)
1297-1371: Add happy-path for authentication_mode: skipInclude a positive test to lock in acceptance of skip mode.
Apply this diff near the end of TestValidateIntrospectionAuthConfig:
@@ t.Run("token too short", func(t *testing.T) { t.Parallel() @@ require.ErrorContains(t, err, "at '/introspection/token': minLength: got 15, want 32") }) + + t.Run("valid config with skip mode", func(t *testing.T) { + t.Parallel() + + f := createTempFileFromFixture(t, ` +version: "1" + +introspection: + enabled: true + authentication_mode: skip +`) + _, err := LoadConfig([]string{f}) + require.NoError(t, err) + })
1297-1371: Add boundary test for token length = 32Prevents regressions on minLength enforcement.
Apply this diff:
@@ t.Run("valid config with token", func(t *testing.T) { t.Parallel() @@ require.NoError(t, err) }) + t.Run("valid token with exact 32 chars", func(t *testing.T) { + t.Parallel() + // 32 'a' characters + f := createTempFileFromFixture(t, ` +version: "1" + +introspection: + enabled: true + authentication_mode: token + token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +`) + _, err := LoadConfig([]string{f}) + require.NoError(t, err) + })
1297-1371: Optional: DRY up YAML fixture generationA tiny helper reduces duplication and makes future cases cheaper to add.
I can push a helper like:
func introspectionYAML(enabled bool, mode, token string) string { tok := "" if token != "" { tok = fmt.Sprintf("\n token: %s", token) } return fmt.Sprintf(` version: "1" introspection: enabled: %t authentication_mode: %s%s `, enabled, mode, tok) }Then subtests can pass createTempFileFromFixture(t, introspectionYAML(true, "token", strings.Repeat("a", 32))).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
router/pkg/config/config_test.go(1 hunks)router/pkg/config/fixtures/full.yaml(1 hunks)router/pkg/config/testdata/config_defaults.json(1 hunks)router/pkg/config/testdata/config_full.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- router/pkg/config/fixtures/full.yaml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-21T14:46:34.879Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/authentication/jwks_token_decoder.go:80-106
Timestamp: 2025-07-21T14:46:34.879Z
Learning: In the Cosmo router project, required field validation for JWKS configuration (Secret, Algorithm, KeyId) is handled at the JSON schema level in config.schema.json rather than through runtime validation in the Go code at router/pkg/authentication/jwks_token_decoder.go.
Applied to files:
router/pkg/config/testdata/config_defaults.json
🧬 Code graph analysis (1)
router/pkg/config/config_test.go (1)
router/pkg/config/config.go (1)
LoadConfig(1098-1210)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build-router
- GitHub Check: build_test
- GitHub Check: image_scan
- GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
- GitHub Check: build_push_image (nonroot)
- GitHub Check: build_push_image
- GitHub Check: integration_test (./telemetry)
- GitHub Check: image_scan (nonroot)
- GitHub Check: integration_test (./events)
- GitHub Check: Analyze (go)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
router/pkg/config/testdata/config_full.json (2)
462-466: IntrospectionConfig snapshot looks correct; placeholder token avoids secret scannersAuthenticationMode: "full" with a ≥32-char placeholder token is fine and aligns with schema; thanks for removing the high-entropy token.
462-466: Docs/PR text: align on “authentication_mode” vs “skip_authentication”PR summary mentions skip_authentication, but the config uses authentication_mode ("full" | "token" | "skip"). Ensure the docs PR reflects the final shape and header expectations for token mode.
router/pkg/config/testdata/config_defaults.json (1)
231-235: Defaults fixture matches new schemaEnabled: true with AuthenticationMode: "full" and empty token is a sensible default. No changes requested.
router/pkg/config/config_test.go (1)
1297-1371: Good coverage of introspection auth schema pathsCovers happy paths (full, token) and key failures (invalid mode, missing token, minLength). Looks solid.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (5)
router-tests/authentication_test.go (1)
42-49: Optional: factor a tiny helper to reduce repetitionAccessControllerOptions blocks repeat across many tests. Consider a small helper (in test utils) to build the controller to DRY this up.
Also applies to: 71-79, 103-111, 138-145, 164-171, 197-204, 232-239, 266-273, 300-308, 340-347, 376-384, 410-417, 441-448, 511-518, 631-639, 665-672, 700-707, 735-742, 770-777, 831-838, 905-911, 933-940, 965-972, 1028-1035, 1095-1101, 1146-1152, 1193-1199, 1241-1247, 1335-1341, 1641-1647, 1731-1737, 1761-1767, 1791-1797, 1826-1832, 1860-1866, 1949-1955, 1986-1992, 2023-2029, 2060-2065, 2097-2103, 2134-2139, 2175-2181, 2212-2217, 2249-2254, 2290-2295, 2331-2336, 2368-2373, 2405-2410, 2444-2450, 2486-2492, 2551-2556, 2599-2605, 2651-2656, 2695-2701, 2756-2761, 2801-2806, 2856-2862, 2901-2906, 2954-2961, 3002-3008
router/core/supervisor_instance.go (2)
73-80: Gate warnings when auth is configured; avoid misleading logsIf there are no authenticators, these warnings can confuse (no auth is enforced at all). Guard them by checking authenticators present.
Apply:
- if cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret == "" { + if len(authenticators) > 0 && cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret == "" { params.Logger.Warn("introspection operations are not authenticated. " + "Consider setting /introspection/secret or set /authentication/ignore_introspection to false. Do not use this in production.") } - if !cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret != "" { + if len(authenticators) > 0 && !cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret != "" { params.Logger.Warn("/introspection/secret is ignored because /authentication/ignore_introspection is false.") }
171-179: Prefer the new nested flag as source of truthPass IntrospectionConfig.Enabled to WithIntrospection to avoid ambiguity with the deprecated boolean.
Apply:
- WithIntrospection(config.IntrospectionEnabled, config.IntrospectionConfig), + WithIntrospection(config.IntrospectionConfig.Enabled, config.IntrospectionConfig),router/core/access_controller.go (2)
35-37: Fix stale constructor comment (no invalid “auth mode”).The comment mentions an introspection auth mode that no longer exists and suggests non-nil errors that aren’t produced.
Apply:
-// NewAccessController creates a new AccessController. -// It returns an error if the introspection auth mode is invalid. +// NewAccessController creates a new AccessController. +// Note: currently returns a nil error; the error return is reserved for future configuration validation.
71-71: Rename unused param to underscore.Communicates intent and appeases linters without API break.
Apply:
-func (a *AccessController) IntrospectionAccess(r *http.Request, body []byte) bool { +func (a *AccessController) IntrospectionAccess(r *http.Request, _ []byte) bool {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (21)
router-tests/authentication_test.go(68 hunks)router-tests/batch_test.go(2 hunks)router-tests/block_operations_test.go(3 hunks)router-tests/header_set_test.go(1 hunks)router-tests/modules/router_on_request_test.go(2 hunks)router-tests/modules/set_authentication_scopes_test.go(3 hunks)router-tests/modules/set_scopes_test.go(2 hunks)router-tests/prometheus_test.go(2 hunks)router-tests/ratelimit_test.go(1 hunks)router-tests/telemetry/telemetry_test.go(14 hunks)router-tests/websocket_test.go(10 hunks)router/core/access_controller.go(3 hunks)router/core/graphql_prehandler.go(7 hunks)router/core/router.go(2 hunks)router/core/supervisor_instance.go(2 hunks)router/pkg/config/config.go(3 hunks)router/pkg/config/config.schema.json(2 hunks)router/pkg/config/config_test.go(1 hunks)router/pkg/config/fixtures/full.yaml(2 hunks)router/pkg/config/testdata/config_defaults.json(2 hunks)router/pkg/config/testdata/config_full.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
- router/pkg/config/testdata/config_defaults.json
- router/pkg/config/config.schema.json
- router-tests/websocket_test.go
- router-tests/block_operations_test.go
- router-tests/telemetry/telemetry_test.go
- router-tests/modules/set_scopes_test.go
- router/pkg/config/testdata/config_full.json
- router/pkg/config/config_test.go
- router/pkg/config/fixtures/full.yaml
- router-tests/batch_test.go
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-09-02T12:52:27.677Z
Learnt from: endigma
PR: wundergraph/cosmo#2181
File: router/core/operation_processor.go:0-0
Timestamp: 2025-09-02T12:52:27.677Z
Learning: Hash validation for persisted queries with query bodies is performed in router/core/graphql_prehandler.go in the handleOperation function, not in the APQ processing logic in operation_processor.go. This validates that extensions.persistedQuery.sha256Hash matches the query body before any APQ operations occur.
Applied to files:
router/core/access_controller.go
📚 Learning: 2025-09-02T12:52:27.677Z
Learnt from: endigma
PR: wundergraph/cosmo#2181
File: router/core/operation_processor.go:0-0
Timestamp: 2025-09-02T12:52:27.677Z
Learning: Hash validation for persisted queries with query bodies is performed in router/core/graphql_prehandler.go in the handleOperation function at lines 571-578, not in the APQ processing logic in operation_processor.go. This validates that extensions.persistedQuery.sha256Hash matches the computed query hash before any APQ operations occur. There's also a test case that verifies this behavior.
Applied to files:
router/core/access_controller.go
📚 Learning: 2025-09-10T12:33:59.146Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/access_controller.go:3-10
Timestamp: 2025-09-10T12:33:59.146Z
Learning: For introspection token authentication in the router, the Authorization header should contain the exact static secret as configured, without Bearer prefix or whitespace normalization. Any deviation should be treated as invalid authentication.
Applied to files:
router/core/access_controller.go
📚 Learning: 2025-09-22T11:13:39.415Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/keyfunc/keyfunc_test.go:167-178
Timestamp: 2025-09-22T11:13:39.415Z
Learning: When reviewing forked code from external libraries, gitleaks warnings for hardcoded test tokens/credentials should typically be ignored as they are legitimate test fixtures from the upstream source, not real sensitive data.
Applied to files:
router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections. The validation store maintains its own internal supported algorithms map that gets returned regardless of input parameters.
Applied to files:
router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections.
Applied to files:
router-tests/authentication_test.go
🧬 Code graph analysis (11)
router-tests/modules/set_authentication_scopes_test.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
WithAccessController(1825-1829)WithIntrospection(1554-1559)
router/pkg/config/config.go (1)
demo/pkg/subgraphs/test1/subgraph/model/models_gen.go (1)
Secret(667-669)
router-tests/ratelimit_test.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router-tests/modules/router_on_request_test.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router-tests/prometheus_test.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (1)
WithAccessController(1825-1829)
router-tests/header_set_test.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (1)
WithAccessController(1825-1829)
router/core/access_controller.go (1)
router/pkg/authentication/authentication.go (1)
Authenticator(22-25)
router/core/router.go (1)
router/pkg/config/config.go (1)
IntrospectionConfiguration(988-991)
router-tests/authentication_test.go (4)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router-tests/testenv/testenv.go (3)
Run(107-124)Config(286-342)Environment(1731-1767)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)router-tests/utils.go (2)
ConfigureAuth(45-57)JwksName(19-19)
router/core/graphql_prehandler.go (2)
router/internal/expr/expr.go (3)
Request(66-75)LoadAuth(183-195)Context(35-39)router/pkg/trace/utils.go (1)
AttachErrToSpan(75-81)
🔇 Additional comments (22)
router-tests/modules/set_authentication_scopes_test.go (3)
35-41: LGTM! Consistent migration to new AccessController API.The changes correctly migrate to the new
core.AccessControllerOptionsstruct pattern, following the same pattern used across the test suite. All required parameters are explicitly set for clarity.
84-90: LGTM! Consistent API usage.
135-141: LGTM! Maintains consistency across all test cases.router/core/router.go (4)
214-219: Ensure consistent deprecation message format.The deprecation messages use different path formats. Consider standardizing to be consistent with the introspection deprecation message format.
#!/bin/bash # Check for all deprecation message formats in the codebase rg -n "option is deprecated.*Use the.*option" --type go
225-233: LGTM! Well-handled deprecation and synchronization logic.The introspection configuration deprecation is handled correctly with proper backward compatibility:
- Logs a deprecation warning when the old option is used
- Synchronizes the configuration between old and new fields
- Ensures either option can disable introspection
1554-1558: LGTM! Correct API update for WithIntrospection.The function signature is properly updated to accept the new introspection configuration structure.
1825-1828: LGTM! Clean implementation of WithAccessController.The option correctly accepts a pre-created AccessController instance.
router-tests/prometheus_test.go (1)
4122-4129: LGTM! Correct migration to new AccessController API.The test properly creates an AccessController with the new options pattern and includes error handling as required.
router-tests/header_set_test.go (1)
278-285: LGTM! Proper migration to new AccessController API.The test correctly uses the new
AccessControllerOptionsstruct and handles the error return value.router-tests/ratelimit_test.go (1)
273-284: LGTM: AccessControllerOptions usage and injectionThe migration to options-based AccessController and injecting it via WithAccessController is correct and consistent with the new API.
Also applies to: 283-283
router-tests/authentication_test.go (2)
3193-3211: Clarify header scheme for introspection secret (optional docs note)Tests use Authorization: (no scheme). Ensure docs clearly state the expected header format to avoid confusion with bearer tokens.
3031-3321: Introspection auth-bypass test coverage — LGTM; verify constructor usageFound multiple NewAccessController references (router/core/access_controller.go:37, router/core/supervisor_instance.go:60, numerous router-tests/*). Confirm these are intended or update them.
router-tests/modules/router_on_request_test.go (1)
8-10: LGTM: import alias and controller wiringAlias import is fine; controller construction and injection align with the new API.
Also applies to: 73-80, 83-86
router/core/supervisor_instance.go (1)
59-71: LGTM: build AccessController from authenticatorsConstruction via AccessControllerOptions and injection is correct.
router/core/graphql_prehandler.go (4)
107-116: Auth-pass tracking for introspection — LGTMThe authenticationPass enum and propagation through httpOperation is clear and keeps downstream checks simple.
Also applies to: 118-126
367-407: Auth flow handling — LGTMSpan lifecycle is correct; success and failure paths end the span, and auth context is only populated on success.
680-709: Authorization gate respects introspection modes — LGTMNon-introspection requires normal auth; introspection allows normal, secret, or skip. Matches tests and the feature design.
1145-1157: Good centralization of auth failure responseShared helper keeps logging, spans, and HTTP response consistent.
router/pkg/config/config.go (1)
496-499: Verify JSON schema documents new introspection fields and deprecationrg search returned no matches in router/pkg/config — cannot confirm schema changes; ensure the JSON schema documents IntrospectionConfiguration (with env mappings), Authentication.ignore_introspection, and a deprecation notice for introspection_enabled (and INTROSPECTION_SECRET env if applicable).
router/core/access_controller.go (3)
19-25: Good move to Options struct.Constructor ergonomics improved; fields are clear.
29-32: Controller fields align with options.No concerns.
64-67: Helper reads well.Clear signal for downstream checks.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (6)
router/pkg/config/fixtures/full.yaml (1)
23-25: Introspection block looks good; add an inline hint to reduce confusionSecret is only honored when authentication.ignore_introspection is true. Add a short comment to make that clear in the fixture.
introspection: enabled: true - secret: 'AN_EXAMPLE_PLACEHOLDER_SECRET_ONLY' + secret: 'AN_EXAMPLE_PLACEHOLDER_SECRET_ONLY' + # Note: secret is only used when authentication.ignore_introspection is truerouter/pkg/config/config.schema.json (2)
1369-1385: Fill missing descriptions for introspection and fix grammarDescriptions are empty; add concise text and improve the secret note.
- "introspection": { - "type": "object", - "description": "", + "introspection": { + "type": "object", + "description": "Configuration for GraphQL introspection.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", - "description": "", + "description": "Enable GraphQL introspection.", "default": true }, "secret": { "type": "string", - "description": "A dedicated secret to authenticate introspection requests independently from the regular authentication. Need to passed by introspection queries via the 'Authorization' header. Works only when authentication.ignore_introspection is true.", + "description": "Optional secret to authenticate introspection requests independently from regular auth. Must be passed via the 'Authorization' header. Effective only when authentication.ignore_introspection is true.", "minLength": 32 } } },Optional (nice-to-have): enforce interaction via an if/then at the root so that when introspection.secret is present, authentication.ignore_introspection must be true.
1851-1855: Fix grammar in ignore_introspection descriptionMinor copy tweak.
- "description": "If the value is true, introspection requests not need to be authenticated. The default value is false.", + "description": "If true, introspection requests do not need to be authenticated. The default value is false.",router/core/supervisor_instance.go (2)
73-77: Update warning logic and messaging to the new config pathUse the new flag and reference /introspection/skip_authentication in the message.
Apply this diff:
- if cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret == "" { - params.Logger.Warn("introspection operations are not authenticated. " + - "Consider setting /introspection/secret or set /authentication/ignore_introspection to false. Do not use this in production.") - } + if cfg.IntrospectionConfig.SkipAuthentication && cfg.IntrospectionConfig.Secret == "" { + params.Logger.Warn("introspection operations are not authenticated. " + + "Consider setting /introspection/secret or set /introspection/skip_authentication to false. Do not use this in production.") + }
78-80: Align second warning with new config pathReference /introspection/skip_authentication instead of the deprecated field.
Apply this diff:
- if !cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret != "" { - params.Logger.Warn("/introspection/secret is ignored because /authentication/ignore_introspection is false.") - } + if !cfg.IntrospectionConfig.SkipAuthentication && cfg.IntrospectionConfig.Secret != "" { + params.Logger.Warn("/introspection/secret is ignored because /introspection/skip_authentication is false.") + }router-tests/authentication_test.go (1)
45-52: Reduce duplication: helper for controller setup in testsConsider a small test helper to build the controller to cut repetition and prevent future drift:
func newAccessControllerForTests(t *testing.T, auths []authentication.Authenticator, required bool, skipIntrospection bool, secret string) *core.AccessController { ac, err := core.NewAccessController(core.AccessControllerOptions{ Authenticators: auths, AuthenticationRequired: required, SkipIntrospectionQueries: skipIntrospection, IntrospectionSkipSecret: secret, }) require.NoError(t, err) return ac }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
router-tests/authentication_test.go(68 hunks)router-tests/header_set_test.go(1 hunks)router/core/supervisor_instance.go(2 hunks)router/pkg/config/config.go(3 hunks)router/pkg/config/config.schema.json(2 hunks)router/pkg/config/fixtures/full.yaml(2 hunks)router/pkg/config/testdata/config_full.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- router/pkg/config/testdata/config_full.json
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.
Applied to files:
router/pkg/config/config.schema.json
📚 Learning: 2025-07-21T14:46:34.879Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/authentication/jwks_token_decoder.go:80-106
Timestamp: 2025-07-21T14:46:34.879Z
Learning: In the Cosmo router project, required field validation for JWKS configuration (Secret, Algorithm, KeyId) is handled at the JSON schema level in config.schema.json rather than through runtime validation in the Go code at router/pkg/authentication/jwks_token_decoder.go.
Applied to files:
router/pkg/config/fixtures/full.yaml
📚 Learning: 2025-09-22T11:13:39.415Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/keyfunc/keyfunc_test.go:167-178
Timestamp: 2025-09-22T11:13:39.415Z
Learning: When reviewing forked code from external libraries, gitleaks warnings for hardcoded test tokens/credentials should typically be ignored as they are legitimate test fixtures from the upstream source, not real sensitive data.
Applied to files:
router/pkg/config/fixtures/full.yamlrouter-tests/authentication_test.go
📚 Learning: 2025-09-22T11:13:45.607Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/keyfunc/keyfunc_test.go:142-154
Timestamp: 2025-09-22T11:13:45.607Z
Learning: When reviewing forked code, especially test files with test fixtures like JWT tokens, avoid suggesting modifications to maintain alignment with upstream and preserve the original author's structure. Test fixtures that are clearly marked as such (not real secrets) should generally be left unchanged in forked implementations.
Applied to files:
router/pkg/config/fixtures/full.yaml
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections. The validation store maintains its own internal supported algorithms map that gets returned regardless of input parameters.
Applied to files:
router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections.
Applied to files:
router-tests/authentication_test.go
🧬 Code graph analysis (4)
router-tests/header_set_test.go (3)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router-tests/testenv/testenv.go (2)
Run(107-124)Config(286-342)router/core/router.go (1)
WithAccessController(1825-1829)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
WithAccessController(1825-1829)WithIntrospection(1554-1559)
router/pkg/config/config.go (1)
demo/pkg/subgraphs/test1/subgraph/model/models_gen.go (1)
Secret(667-669)
router-tests/authentication_test.go (4)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router-tests/testenv/testenv.go (3)
Run(107-124)Config(286-342)Environment(1731-1767)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)router-tests/utils.go (2)
ConfigureAuth(45-57)JwksName(19-19)
🪛 GitHub Actions: Router CI
router-tests/authentication_test.go
[error] 91-91: go vet failed: ./authentication_test.go:91:72: too many arguments in call to core.NewAccessController
🔇 Additional comments (11)
router/pkg/config/fixtures/full.yaml (2)
273-273: New flag placement LGTMauthentication.ignore_introspection defaults are explicit here; fine for a “full” fixture.
277-287: JWKS options extension LGTMrefresh_interval, algorithms, and refresh_unknown_kid match the schema and code. Good sample coverage.
router/pkg/config/config.go (2)
505-507: Expose ignore_introspection on Authentication: LGTMField surfaces the new behavior cleanly; no env tag avoids precedence confusion.
996-999: IntrospectionConfiguration addition: LGTMYAML/env tags are consistent and align with the schema.
router/pkg/config/config.schema.json (2)
1360-1361: Clear deprecation message for playground_enabled: LGTMGood guidance toward playground.enabled.
1365-1368: introspection_enabled deprecation: LGTMDefaults and message are clear.
router/core/supervisor_instance.go (1)
59-71: Wire introspection.skip_authentication (keep back‑compat) and initialize AccessController when appropriate
- Replace usage of cfg.Authentication.IgnoreIntrospection with cfg.IntrospectionConfig.SkipAuthentication OR them for back‑compat; set SkipIntrospectionQueries accordingly (router/core/supervisor_instance.go:59-71).
- Instantiate AccessController when any of these are true: cfg.Authorization.RequireAuthentication || cfg.IntrospectionConfig.SkipAuthentication || cfg.IntrospectionConfig.Secret != "" || len(authenticators) > 0 (same file).
- Adjust the warning logic that currently compares cfg.Authentication.IgnoreIntrospection and cfg.IntrospectionConfig.Secret (router/core/supervisor_instance.go:73-80) to account for the new SkipAuthentication flag.
- Note: repository search shows no usages of IntrospectionConfig.SkipAuthentication — confirm this config field exists (or add it) before applying; current code only references cfg.Authentication.IgnoreIntrospection.
router-tests/header_set_test.go (1)
278-285: Options-based AccessController wiring looks correctConstructing via AccessControllerOptions and injecting with WithAccessController(accessController) is aligned with the new API and asserts errors properly.
Also applies to: 292-293
router-tests/authentication_test.go (3)
29-36: Good test constants for introspection coverageThe added constants make the new cases clear and reusable.
45-52: Nice migration to options-based NewAccessController across testsConsistent construction with error checks and explicit SkipIntrospectionQueries/IntrospectionSkipSecret improves clarity.
Also applies to: 401-407, 433-440, 468-474, 493-500, 527-533, 562-568, 596-602, 631-637, 670-676, 707-713, 740-746, 771-777, 806-812, 841-847, 878-884, 905-911, 932-939, 961-967, 993-1001, 1029-1036, 1065-1071, 1099-1106, 1160-1167, 1357-1364, 1423-1430, 1474-1481, 1521-1528, 1571-1576, 1663-1670, 1802-1809, 1838-1845, 1969-1976, 2061-2068, 2091-2098, 2121-2128, 2155-2161, 2189-2195, 2278-2284, 2315-2321, 2352-2358, 2389-2395, 2426-2432, 2463-2469, 2504-2510, 2541-2547, 2578-2584, 2619-2625, 2660-2666, 2697-2703, 2734-2740, 2773-2779, 2834-2840, 2880-2886, 2927-2933, 2979-2985, 3024-3030, 3085-3091, 3130-3136, 3186-3192, 3230-3236, 3284-3290, 3331-3337
3360-3650: Introspection auth-bypass tests cover key paths; confirm Authorization formatCoverage looks solid: POST/GET detection, bypass with/without bearer JWT, and secret-gated mode. One verification: should the secret be accepted both as "Authorization: " and "Authorization: Bearer "? If only one is supported, add/adjust a test to lock the contract.
…ion-endpoint-from-auth
a792387 to
77a2517
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
router-tests/authentication_test.go (1)
44-56: Reduce test duplication: extract AccessController builder helperThe options-based AccessController construction repeats throughout the file. Consider a small test helper to DRY it up.
Example helper (place in this package’s test utils):
func newAccessControllerForTests(t *testing.T, authenticators []authentication.Authenticator, requireAuth, skipIntrospection bool, secret string) *core.AccessController { t.Helper() ac, err := core.NewAccessController(core.AccessControllerOptions{ Authenticators: authenticators, AuthenticationRequired: requireAuth, SkipIntrospectionQueries: skipIntrospection, IntrospectionSkipSecret: secret, }) require.NoError(t, err) return ac }Then replace repeated blocks with:
accessController := newAccessControllerForTests(t, authenticators, true, false, "")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
router-tests/authentication_test.go(74 hunks)router-tests/header_set_test.go(1 hunks)router/core/supervisor_instance.go(2 hunks)router/pkg/config/config.go(3 hunks)router/pkg/config/config.schema.json(2 hunks)router/pkg/config/fixtures/full.yaml(2 hunks)router/pkg/config/testdata/config_full.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- router-tests/header_set_test.go
- router/pkg/config/testdata/config_full.json
- router/pkg/config/fixtures/full.yaml
- router/pkg/config/config.go
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-09-22T11:13:39.415Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/keyfunc/keyfunc_test.go:167-178
Timestamp: 2025-09-22T11:13:39.415Z
Learning: When reviewing forked code from external libraries, gitleaks warnings for hardcoded test tokens/credentials should typically be ignored as they are legitimate test fixtures from the upstream source, not real sensitive data.
Applied to files:
router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections. The validation store maintains its own internal supported algorithms map that gets returned regardless of input parameters.
Applied to files:
router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections.
Applied to files:
router-tests/authentication_test.go
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.
Applied to files:
router/pkg/config/config.schema.json
🧬 Code graph analysis (2)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
WithAccessController(1825-1829)WithIntrospection(1554-1559)
router-tests/authentication_test.go (3)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)router-tests/utils.go (2)
ConfigureAuth(45-57)JwksName(19-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build-router
- GitHub Check: build_push_image
- GitHub Check: integration_test (./telemetry)
- GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
- GitHub Check: integration_test (./events)
- GitHub Check: build_test
- GitHub Check: build_push_image (nonroot)
- GitHub Check: image_scan (nonroot)
- GitHub Check: image_scan
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (go)
🔇 Additional comments (5)
router/pkg/config/config.schema.json (2)
1360-1360: LGTM: clearer playground deprecation message.
1365-1368: LGTM: deprecate introspection_enabled with migration hint.router-tests/authentication_test.go (2)
3408-3698: Introspection auth-bypass tests look solidGood coverage across POST/GET, valid/invalid bearer, and token-required scenarios.
3584-3596: Confirm Authorization header scheme for introspection tokenTests send the raw secret (no "Bearer " prefix). Ensure AccessController and docs expect this exact scheme.
router/core/supervisor_instance.go (1)
177-177: Use introspection.enabled (fallback to deprecated flag)Enable introspection if either the new or deprecated flag is true.
- WithIntrospection(config.IntrospectionEnabled, config.IntrospectionConfig), + WithIntrospection(config.IntrospectionConfig.Enabled || config.IntrospectionEnabled, config.IntrospectionConfig),
…ion-endpoint-from-auth
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
router/pkg/config/config.go (1)
506-508: Unify introspection auth config; avoid split/precedence pitfallsYou’re introducing both Authentication.IgnoreIntrospection and a new Introspection section. This can create ambiguous precedence (e.g., ignore_introspection=true vs. requiring a secret/token under introspection). Prefer a single source of truth under Introspection to steer auth behavior and mark ignore_introspection as deprecated, or wire clear precedence in post-processing. Also, the PR narrative uses “token”, while the struct uses “secret” — that’s a doc/schema drift risk.
Recommended:
- Consolidate knobs under Introspection (e.g., authentication_mode: full|token|skip and token).
- Keep current fields for compatibility but document precedence and deprecations.
If you keep both for now, please confirm schema/docs reflect the final shape and precedence.
Minimal schema-alignment patch (add token alias and optional mode without breaking existing secret/env):
type IntrospectionConfiguration struct { - Enabled bool `yaml:"enabled" envDefault:"true" env:"INTROSPECTION_ENABLED"` - Secret string `yaml:"secret" env:"INTROSPECTION_SECRET"` + Enabled bool `yaml:"enabled" envDefault:"true" env:"INTROSPECTION_ENABLED"` + // Token preferred in docs; keep Secret for back-compat with env while we transition. + Token string `yaml:"token,omitempty" env:"INTROSPECTION_TOKEN"` + Secret string `yaml:"secret,omitempty" env:"INTROSPECTION_SECRET"` // deprecated + AuthenticationMode string `yaml:"authentication_mode,omitempty" env:"INTROSPECTION_AUTHENTICATION_MODE"` // allowed: full|token|skip }Optionally mark the new Authentication.IgnoreIntrospection as deprecated in favor of introspection.authentication_mode=skip, or move it under Introspection to avoid scattering related knobs.
Also applies to: 997-1000, 1028-1029
router-tests/websocket_test.go (1)
139-146: Adoption of AccessControllerOptions is correct; reduce duplication with a tiny helperThe per-test construction/injection of AccessController is repetitive but otherwise solid. Extract a helper to cut noise and make intent clearer.
Example helper for this file:
func newAccessControllerForTests(t *testing.T, auths []authentication.Authenticator, required bool) *core.AccessController { t.Helper() ac, err := core.NewAccessController(core.AccessControllerOptions{ Authenticators: auths, AuthenticationRequired: required, // Defaults for introspection behavior; override per test if needed. }) require.NoError(t, err) return ac }Then replace blocks like:
accessController, err := core.NewAccessController(core.AccessControllerOptions{ ... }) require.NoError(t, err) ... core.WithAccessController(accessController),with:
core.WithAccessController(newAccessControllerForTests(t, authenticators, false)),This trims several hundred repeated lines without changing behavior. Based on learnings.
Also applies to: 149-149, 196-203, 206-206, 252-259, 264-264, 318-325, 330-330, 384-390, 399-399, 453-459, 466-466, 509-515, 522-522, 916-923, 945-945
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
router-tests/websocket_test.go(10 hunks)router/pkg/config/config.go(3 hunks)router/pkg/config/config.schema.json(2 hunks)router/pkg/config/testdata/config_defaults.json(2 hunks)router/pkg/config/testdata/config_full.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- router/pkg/config/testdata/config_defaults.json
- router/pkg/config/testdata/config_full.json
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-23T16:27:54.358Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/supervisor_instance.go:59-71
Timestamp: 2025-09-23T16:27:54.358Z
Learning: In the router codebase, AccessController creation follows a nil pattern where accessController == nil signals that no authentication should be performed. Other parts of the code (like the prehandler) check for accessController == nil to determine whether to skip authentication entirely. Always creating an AccessController would break this pattern and cause authentication to be attempted even when no authenticators are configured.
Applied to files:
router-tests/websocket_test.go
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.
Applied to files:
router/pkg/config/config.schema.json
🧬 Code graph analysis (1)
router-tests/websocket_test.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: build-router
- GitHub Check: build_push_image (nonroot)
- GitHub Check: build_push_image
- GitHub Check: image_scan (nonroot)
- GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
- GitHub Check: integration_test (./telemetry)
- GitHub Check: integration_test (./events)
- GitHub Check: image_scan
- GitHub Check: build_test
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (go)
- GitHub Check: build_test
🔇 Additional comments (4)
router/pkg/config/config.schema.json (4)
1360-1360: Deprecation message for playground_enabled: LGTM.Message clearly points to playground.enabled.
1365-1368: introspection_enabled deprecation path: LGTM.Keeps default and directs users to introspection.enabled.
1369-1384: Fill descriptions, fix secret wording, and avoid hard minLength in schema (warn in Go instead).
- Add a meaningful description for introspection.
- Use dot-path in secret description and note intended local/dev use.
- Remove minLength: 32 here and validate length with a warning in Go to preserve flexibility. Based on learnings.
Apply:
"introspection": { "type": "object", - "description": "", + "description": "Configuration for GraphQL introspection. Not recommended for production; see documentation.", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Enable the GraphQL introspection. The GraphQL introspection allows you to query the schema of the GraphQL API. The default value is true. If the value is false, the GraphQL introspection is disabled. In production, it is recommended to disable the introspection.", "default": true }, "secret": { "type": "string", - "description": "A dedicated secret to protect introspection when skipping standard authentication. Needs to be passed via the 'Authorization' header. Effective only when /authentication/ignore_introspection is true.", - "minLength": 32 + "description": "A dedicated secret to protect introspection when skipping standard authentication. Needs to be passed via the 'Authorization' header. Effective only when authentication.ignore_introspection is true. Intended for local/dev use." } } }Optionally, enforce the interplay in Go validation (emit warning/errors on misuse) instead of schema constraints to maintain backward compatibility. Based on learnings.
1851-1855: Grammar fix for ignore_introspection description.Use “do not need to be authenticated.”
"ignore_introspection": { "type": "boolean", - "description": "If the value is true, introspection requests not need to be authenticated. The default value is false.", + "description": "If true, introspection requests do not need to be authenticated. The default value is false.", "default": false }
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
router/core/supervisor_instance.go(2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-29T10:28:07.088Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/pkg/config/config.go:1028-1029
Timestamp: 2025-09-29T10:28:07.088Z
Learning: The deprecation strategy for IntrospectionEnabled field in router/pkg/config/config.go is to first mark it as deprecated, then migrate all call sites to use IntrospectionConfig.Enabled, and finally remove the deprecated field. The envDefault tag should be kept during the deprecation period for backward compatibility.
Applied to files:
router/core/supervisor_instance.go
📚 Learning: 2025-09-23T16:27:54.358Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/supervisor_instance.go:59-71
Timestamp: 2025-09-23T16:27:54.358Z
Learning: In the router codebase, AccessController creation follows a nil pattern where accessController == nil signals that no authentication should be performed. Other parts of the code (like the prehandler) check for accessController == nil to determine whether to skip authentication entirely. Always creating an AccessController would break this pattern and cause authentication to be attempted even when no authenticators are configured.
Applied to files:
router/core/supervisor_instance.go
🧬 Code graph analysis (1)
router/core/supervisor_instance.go (3)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/pkg/authentication/authentication.go (1)
Authentication(27-40)router/core/router.go (2)
WithAccessController(1825-1829)WithIntrospection(1554-1559)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build-router
- GitHub Check: integration_test (./telemetry)
- GitHub Check: build_push_image (nonroot)
- GitHub Check: image_scan
- GitHub Check: build_push_image
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: image_scan (nonroot)
- GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
- GitHub Check: integration_test (./events)
- GitHub Check: Analyze (go)
- GitHub Check: build_test
🔇 Additional comments (2)
router/core/supervisor_instance.go (2)
73-80: Remove or revise references to non-existent IntrospectionConfig fields
The IntrospectionConfiguration struct only definesEnabledandSecret; there are noSkipAuthenticationorTokenfields to reference in these warnings.Likely an incorrect or invalid review comment.
177-177: Honor bothIntrospectionConfig.Enabledand deprecatedIntrospectionEnabledwhen invokingWithIntrospection- WithIntrospection(config.IntrospectionEnabled, config.IntrospectionConfig), + WithIntrospection(config.IntrospectionConfig.Enabled || config.IntrospectionEnabled, config.IntrospectionConfig),
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
router-tests/authentication_test.go (1)
3394-3394: Complete the AccessController API migration.These calls still use the deprecated positional constructor
core.NewAccessController(authenticators, bool)instead of the new options-based API used throughout the rest of the file. For consistency and to follow the migration pattern, update these to usecore.AccessControllerOptions.Apply this pattern (example for line 3394):
- core.WithAccessController(core.NewAccessController(authenticators, true)), + accessController, err := core.NewAccessController(core.AccessControllerOptions{ + Authenticators: authenticators, + AuthenticationRequired: true, + SkipIntrospectionQueries: false, + IntrospectionSkipSecret: "", + }) + require.NoError(t, err) + + testenv.Run(t, &testenv.Config{ + RouterOptions: []core.Option{ + core.WithAccessController(accessController), + },Repeat this pattern for lines 3440, 3525, 3569, 3604, and 3656.
Also applies to: 3440-3440, 3525-3525, 3569-3569, 3604-3604, 3656-3656
♻️ Duplicate comments (7)
router/pkg/config/config.schema.json (1)
1860-1863: Fix grammar in ignore_introspection description.The sentence should read “introspection requests do not need to be authenticated.” Please adjust the wording.
- "description": "If the value is true, introspection requests not need to be authenticated. The default value is false.", + "description": "If the value is true, introspection requests do not need to be authenticated. The default value is false.",router-tests/telemetry/telemetry_test.go (6)
9106-9112: Same refactor applies here (omit zero-values / optional helper)Also applies to: 9125-9125
9161-9168: Same refactor applies here (omit zero-values / optional helper)Also applies to: 9180-9180
9243-9249: Same refactor applies here (omit zero-values / optional helper)Also applies to: 9272-9272
9326-9332: Same refactor applies here (omit zero-values / optional helper)Also applies to: 9347-9347
9392-9398: Same refactor applies here (omit zero-values / optional helper)Also applies to: 9411-9411
9601-9606: Same refactor applies here (omit zero-values / optional helper)Also applies to: 9625-9625
🧹 Nitpick comments (3)
router/core/graphql_prehandler.go (1)
646-675: Consider simplifying the nested conditionals.The validation logic is correct but could be more readable with early returns or a helper function.
Optional refactor for improved readability:
if h.accessController != nil { - // Based on the authentication result, the introspection config, - // and wether this is an introspection query, - // we decide here if we need to abort the request or not. isIntrospection, err := operationKit.isIntrospectionQuery() if err != nil { requestContext.logger.Error("failed to check if operation is introspection, treat it like non-introspection operation", zap.Error(err)) isIntrospection = false } - // non-introspection queries are only allowed when authenticated via normal authentication - if !isIntrospection && httpOperation.authenticationPass != authenticationPassNormal { + // Determine if authentication is sufficient for this operation type + authAllowed := false + if !isIntrospection { + // Non-introspection requires normal authentication + authAllowed = (httpOperation.authenticationPass == authenticationPassNormal) + } else { + // Introspection allows normal auth, secret auth, or skip + authAllowed = (httpOperation.authenticationPass == authenticationPassNormal || + httpOperation.authenticationPass == authenticationPassIntrospectionSecret || + httpOperation.authenticationPass == authenticationPassSkip) + } + + if !authAllowed { return &httpGraphqlError{ message: "unauthorized", statusCode: http.StatusUnauthorized, } } - - // introspection queries are only allowed when authenticated normally or via dedicated token, or when auth skip is enabled - // note: httpOperation.authMethod is only set when authentication is successful and the config allows such authentication. - if isIntrospection && - httpOperation.authenticationPass != authenticationPassNormal && - httpOperation.authenticationPass != authenticationPassIntrospectionSecret && - httpOperation.authenticationPass != authenticationPassSkip { - return &httpGraphqlError{ - message: "unauthorized", - statusCode: http.StatusUnauthorized, - } - } }router/pkg/config/config.schema.json (1)
1374-1388: Document the introspection block.The new
introspectionobject currently has an empty description. Please add a short explanation (e.g., that it configures GraphQL introspection and is not recommended for production) so the schema docs stay usable.router-tests/telemetry/telemetry_test.go (1)
9047-9054: Good adoption of NewAccessController and WithAccessController; remove redundant zero‑values and consider a small helper
- The usage is correct. You can drop explicit zero‑value options to reduce noise (bool false, empty string).
- Given the repetition across this file, consider a tiny test helper to construct the controller once.
Suggested minimal change here:
-accessController, err := core.NewAccessController(core.AccessControllerOptions{ - Authenticators: authenticators, - AuthenticationRequired: false, - SkipIntrospectionQueries: false, - IntrospectionSkipSecret: "", -}) +accessController, err := core.NewAccessController(core.AccessControllerOptions{ + Authenticators: authenticators, +}) require.NoError(t, err)Optionally, introduce a helper and use it at call sites:
// in this package (test file), for reuse func newTestAccessController(t *testing.T, authenticators []authentication.Authenticator) *core.AccessController { ac, err := core.NewAccessController(core.AccessControllerOptions{ Authenticators: authenticators, // AuthenticationRequired false by default; add fields here only if a test needs them. }) require.NoError(t, err) return ac }Then:
-accessController, err := core.NewAccessController(core.AccessControllerOptions{ ... }) -require.NoError(t, err) +accessController := newTestAccessController(t, authenticators)Also applies to: 9068-9068
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
router-tests/authentication_test.go(74 hunks)router-tests/batch_test.go(2 hunks)router-tests/block_operations_test.go(3 hunks)router-tests/ratelimit_test.go(1 hunks)router-tests/telemetry/telemetry_test.go(14 hunks)router-tests/testenv/testenv.go(1 hunks)router/core/graphql_prehandler.go(6 hunks)router/core/router.go(2 hunks)router/core/supervisor_instance.go(2 hunks)router/pkg/config/config.go(3 hunks)router/pkg/config/config.schema.json(2 hunks)router/pkg/config/testdata/config_defaults.json(2 hunks)router/pkg/config/testdata/config_full.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- router-tests/batch_test.go
- router-tests/testenv/testenv.go
- router/pkg/config/testdata/config_full.json
- router-tests/block_operations_test.go
- router/pkg/config/testdata/config_defaults.json
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-29T10:28:07.122Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/pkg/config/config.go:1028-1029
Timestamp: 2025-09-29T10:28:07.122Z
Learning: The deprecation strategy for IntrospectionEnabled field in router/pkg/config/config.go is to first mark it as deprecated, then migrate all call sites to use IntrospectionConfig.Enabled, and finally remove the deprecated field. The envDefault tag should be kept during the deprecation period for backward compatibility.
Applied to files:
router/core/supervisor_instance.gorouter/pkg/config/config.schema.jsonrouter/pkg/config/config.gorouter/core/router.go
📚 Learning: 2025-09-23T16:27:54.358Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/supervisor_instance.go:59-71
Timestamp: 2025-09-23T16:27:54.358Z
Learning: In the router codebase, AccessController creation follows a nil pattern where accessController == nil signals that no authentication should be performed. Other parts of the code (like the prehandler) check for accessController == nil to determine whether to skip authentication entirely. Always creating an AccessController would break this pattern and cause authentication to be attempted even when no authenticators are configured.
Applied to files:
router/core/supervisor_instance.go
🧬 Code graph analysis (6)
router-tests/ratelimit_test.go (3)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router-tests/testenv/testenv.go (2)
Run(107-124)Config(286-343)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (2)
WithAccessController(1825-1829)WithIntrospection(1554-1559)
router-tests/authentication_test.go (4)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router-tests/testenv/testenv.go (4)
Run(107-124)Config(286-343)Environment(1733-1769)GraphQLRequest(1909-1917)router/core/router.go (2)
Option(172-172)WithAccessController(1825-1829)router-tests/utils.go (2)
ConfigureAuth(45-57)JwksName(19-19)
router-tests/telemetry/telemetry_test.go (2)
router/core/access_controller.go (2)
NewAccessController(37-44)AccessControllerOptions(20-25)router/core/router.go (1)
WithAccessController(1825-1829)
router/core/graphql_prehandler.go (2)
router/internal/expr/expr.go (3)
Request(66-75)LoadAuth(189-201)Context(35-39)router/pkg/trace/utils.go (1)
AttachErrToSpan(75-81)
router/core/router.go (1)
router/pkg/config/config.go (1)
IntrospectionConfiguration(999-1002)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
- GitHub Check: build-router
- GitHub Check: build_test
- GitHub Check: image_scan
- GitHub Check: build_push_image
- GitHub Check: build_push_image (nonroot)
- GitHub Check: image_scan (nonroot)
- GitHub Check: integration_test (./events)
- GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
- GitHub Check: integration_test (./telemetry)
- GitHub Check: build_test
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (go)
🔇 Additional comments (15)
router/core/graphql_prehandler.go (3)
111-129: LGTM: Clean authentication pass tracking.The
authenticationPassenum and its integration intohttpOperationprovide a clear way to track the authentication outcome through the request lifecycle. The four states (none, normal, introspection secret, skip) cover all the scenarios introduced by the introspection bypass feature.
341-396: Well-designed two-stage authentication approach.The early authentication (before parsing) is necessary to determine the authentication pass type, while the actual enforcement is deferred until after parsing when we know the operation type. This design correctly handles:
- Early rejection (lines 357-364): When auth fails and introspection skip is disabled
- Secret validation (lines 366-375): Constant-time comparison when introspection secret is configured
- Pass tracking (lines 372, 374, 379): Stores the authentication outcome for later validation
The separation of authentication attempt and authorization decision is the right approach for this use case.
1142-1154: Good refactoring: consolidated error handling.The
handleAuthenticationFailurehelper eliminates code duplication and ensures consistent error handling across authentication failure paths.router-tests/ratelimit_test.go (1)
273-283: LGTM: Correct migration to new AccessController API.The test correctly adopts the options-based construction pattern with proper error handling and injection via
WithAccessController.router/core/router.go (2)
225-232: LGTM: Proper deprecation handling with correct config path references.The introspection config deprecation correctly:
- Uses dot notation for config paths (addressing past review feedback)
- Synchronizes values bidirectionally to ensure consistency
- Emits warnings only when the deprecated field is explicitly set to false
1554-1558: LGTM: WithIntrospection signature updated correctly.The function now accepts both the enable flag and the introspection config struct, properly storing both values in the router.
router/core/supervisor_instance.go (3)
59-71: LGTM: Correct AccessController construction maintaining nil pattern.The code correctly:
- Maintains the nil AccessController pattern when no authenticators are configured (as per retrieved learnings)
- Uses the new options-based API with proper error handling
- Wires the introspection skip flag and secret from the correct config locations
Based on learnings
73-80: LGTM: Clear warning messages with correct config references.The warnings properly:
- Use dot notation for config paths (addressing past review feedback)
- Guide users to the correct configuration parameters
- Cover both misconfiguration scenarios (skip without secret, secret without skip)
177-177: LGTM: WithIntrospection call updated correctly.The call properly passes both the legacy enabled flag and the new introspection config struct, matching the updated signature in
router/core/router.go.router/pkg/config/config.go (3)
508-510: LGTM: Authentication configuration extended for introspection control.The new
IgnoreIntrospectionfield enables fine-grained control over introspection authentication behavior, with a safe default offalse(authentication required).
999-1002: LGTM: Clean introspection configuration structure.The new
IntrospectionConfigurationtype provides a structured way to configure introspection with optional secret-based authentication. The default ofenabled: truemaintains backward compatibility.
1030-1031: LGTM: Deprecation handled correctly.The deprecated
IntrospectionEnabledfield retains itsenvDefault:"true"for backward compatibility while the newIntrospectionConfigfield provides structured configuration. The env var collision has been properly resolved (deprecated field no longer reads from env).Based on learnings.
router-tests/authentication_test.go (3)
31-38: LGTM: Well-defined test constants.The new introspection test constants follow existing naming conventions and provide clear, simple test data for verifying introspection authentication behavior.
47-57: LGTM: Clean migration to options-based API.The AccessController construction has been correctly migrated to the new options-based API with proper error handling. The explicit field initialization makes the configuration clear and maintainable.
3679-3969: LGTM: Comprehensive introspection authentication test coverage.The new test suite thoroughly validates introspection authentication behavior across multiple scenarios:
- Full authentication requirement enforcement
- Authentication skip for introspection queries
- HTTP GET and POST method handling
- Token validation precedence over skip
- Secret-based introspection access
- Isolation between introspection and normal queries
The test cases are well-structured, clearly named, and cover both positive and negative paths.
Previous merge with main overwrote some code changes from this commit.
|
This PR was marked stale due to lack of activity. It will be closed in 14 days. |
…ion-endpoint-from-auth
…ion-endpoint-from-auth
Summary by CodeRabbit
New Features
Configuration
Chores
Tests
Checklist
Marked this PR as draft since I want to create a docs PR before this is here is ready for review.
Motivation and Context
This pull requests adds the ability to configure the router to bypass authentication, if the operation is identified as an introspection query. Optionally a separate, static secret for introspection can be configured, which has to be passed via
Authorizationheader instead of the usual JWT token when an introspection query is sent.The motivation behind this feature is that it allows users to configure GraphQL client tooling without the need to acquire valid auth tokens first, which sometimes is not easy in this scenario. It's meant to be used locally. This should not be enabled in production.
To enable this feature I added a new section to the router configuration called
introspection:Changes
introspection_enabledis marked as deprecatedintrospectionwith three child parameters, as described above, addedAccessControlleris extended to know wether introspection auth bypass is enabled and what the secret isAccessControllerprovides a method to check wether the incoming operation is an introspection query (using a temporaryOperationKit) and based on it's configuration, if it should be bypassedPreHandlerfirst checks viaAccessControllerif authentication should be bypassed and skips it if truerouter-teststo disable this feature for all existing tests (to reflect the default config)router-teststo test authentication when this feature is enabled